﻿using Lidgren.Network;
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using UnityEngine;
public class NetHandler : SingletonMono<NetHandler> {

    public int port = 55640;
    public string host = "127.0.0.1";
    // Use this for initialization
    NetChannel netChannel;
    public bool isServer;//判定是否是房主

    public NetOutgoingMessage CreateMessage()
    {
        return netChannel.CreateMessage();
    }
    public void InitNet(bool isBindPort)
    {
        NetPeerConfiguration config = new NetPeerConfiguration("TankNet");
        if(isBindPort)
            config.Port = port;
        config.EnableMessageType(NetIncomingMessageType.DiscoveryRequest);
        config.EnableMessageType(NetIncomingMessageType.DiscoveryResponse);
        config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
        netChannel = new NetChannel(config);
        netChannel.Start();
        Log.InfoFormat("InitNet, isBindPort :{0} ,port {1} ", Log.Color_Purple,isBindPort,port);
    }

    public void Close()
    {
        if(netChannel != null)
        {
            Log.Info("Close NetChannel " , Log.Color_Purple);
            netChannel.Shutdown("Shut Down");
            netChannel = null;
        }
          
    }

    #region 房间操作
    public void CheckRoom()
    {
        if(netChannel != null)
        {
            netChannel.DiscoverLocalPeers(port);
           // Log.Info("RoomMgr.CheckRoom");
        }
    }
    public void CreateRoom()
    {
        if(netChannel!=null)
            Close();

        InitNet(true);
    }
    public void QuitRoom()
    {
        if (netChannel != null)
            Close();

        InitNet(false);
    }
    public void JoinRoom(RoomData room)
    {
        // room.owner. 
        string host = room.owner.ipAddress;
        int port = room.owner.port;

        NetOutgoingMessage msg = netChannel.CreateMessage();
        msg.Write("TankNet");
        msg.Write(NetConst.JoinRoom);
        msg.Write(Global.Instantce.Actor.ToString());
        netChannel.Connect(host, port,msg);
    }
    #endregion
    private void OnApplicationQuit()
    {
        Close();
    }
    // Update is called once per frame
    void Update () {
        if (netChannel == null)
            return;

        NetIncomingMessage msg;
        while ((msg = netChannel.ReadMessage()) != null)
        {
            // process message here
            switch (msg.MessageType)
            {
                case NetIncomingMessageType.VerboseDebugMessage:
                case NetIncomingMessageType.DebugMessage:
                    string log_Debug = msg.ReadString();
                    Log.Info(log_Debug, string.Empty);
                    break;
                case NetIncomingMessageType.WarningMessage:
                    string log_Warning = msg.ReadString();
                    Log.Warning(log_Warning, string.Empty);
                    break;
                case NetIncomingMessageType.ErrorMessage:
                    string log_error = msg.ReadString();
                    Log.Error(log_error, string.Empty);
                    break;
                case NetIncomingMessageType.DiscoveryRequest:
                    OnHandleDiscoveryRequest(msg);
                    break;
                case NetIncomingMessageType.DiscoveryResponse:
                    OnHandleDiscoveryResponse(msg);
                    break;
                case NetIncomingMessageType.Data:
                    OnHandleData(msg);
                    break;
                case NetIncomingMessageType.StatusChanged:
                    OnHandleStautsChange(msg);
                    break;
                case NetIncomingMessageType.ConnectionApproval:
                    OnHandleConnectionApproval(msg);
                    break;
                default:
                    
                    break;
            }
            netChannel.Recycle(msg);
        }   
    }
    /// <summary>
    /// 连接以前的处理，可以处理连接的许可
    /// </summary>
    /// <param name="msg"></param>
    void OnHandleConnectionApproval(NetIncomingMessage msg)
    {
        var secret = msg.ReadString();
        if(!secret.Equals("TankNet"))
        {
            Log.WarningFormat("No Know connection Request  , from :{0}", "", msg.SenderEndPoint.ToString());
            msg.SenderConnection.Deny();
            return;
        }


        var netConst = msg.ReadByte();
        var actor_data_raw = msg.ReadString();
        Log.InfoFormat("{0},{1}", Log.Color_Purple, netConst, actor_data_raw);
        switch(netConst)
        {
            case NetConst.JoinRoom:
                //如果已经满员，则不能加入
                var curRoom = RoomMgr.Instantce.curRoom;
                if(curRoom.allPlayers.Count >= RoomMgr.Instantce.curRoom.map.maxPlayer)
                {
                    msg.SenderConnection.Deny();
                    return;
                }
                break;
        }

        NetOutgoingMessage approve_hailMsg = netChannel.CreateMessage();
        approve_hailMsg.Write("TankNet");
        approve_hailMsg.Write(NetConst.ConnectResp);
        approve_hailMsg.Write(Global.Instantce.Actor.ToString());
        msg.SenderConnection.Approve(approve_hailMsg);
    }

    /// <summary>
    /// 连接状态的改变，包括有新的连接，断开等
    /// </summary>
    /// <param name="msg"></param>
    void OnHandleStautsChange(NetIncomingMessage msg)
    {
        NetConnectionStatus status = (NetConnectionStatus)msg.ReadByte();
        string reason = msg.ReadString();
        Log.InfoFormat("EndPoint :{0} ,status {1} , reason :{2}", Log.Color_Purple, msg.SenderEndPoint, status , reason);
        if (status == NetConnectionStatus.Connected) //连接成功
        {
            OnHandlerConnection(msg);
        }
        else if (status == NetConnectionStatus.Disconnected)
        {
            OnHandlerDisConnection(msg);
        }
    }

    /// <summary>
    /// 处理 收到的局域网广播信息
    /// </summary>
    /// <param name="msg"></param>
    void OnHandleDiscoveryRequest(NetIncomingMessage msg)
    {
        if (RoomMgr.Instantce.isMyRoom)
        {
            NetOutgoingMessage response = netChannel.CreateMessage();
            response.Write("TankNet");
            var room_data = RoomMgr.Instantce.curRoom.ToString();
            response.Write(room_data);
            Log.InfoFormat("DiscoveryRequest , sender {0}", Log.Color_Purple, msg.SenderEndPoint.Address.ToString());
            if(!msg.SenderEndPoint.Address.ToString() .Equals( "127.0.0.1"))
                netChannel.SendDiscoveryResponse(response, msg.SenderEndPoint);
        }
    }

    /// <summary>
    /// 处理 局域网广播信息的响应
    /// </summary>
    /// <param name="msg"></param>
    void OnHandleDiscoveryResponse(NetIncomingMessage msg)
    {
        var netName = msg.ReadString();
        var room_data_raw = msg.ReadString();
        string ip = msg.SenderEndPoint.Address.ToString();
        int port = msg.SenderEndPoint.Port;
        var room_data_in = JsonConvert.DeserializeObject<RoomData>(room_data_raw);
        if (room_data_in == null)
        {
            Log.Error("room Data Cant not be Null");
            return;
        }
        room_data_in.owner.ipAddress = ip;
        room_data_in.owner.port = port;
        
        RoomMgr.Instantce.HandlerDiscoverRoom(room_data_in);
    }

    void OnHandlerConnection(NetIncomingMessage msg)
    {
        var im = msg.SenderConnection.RemoteHailMessage;
        if (im != null)
        {
            im.Position = 0;
            var secret = im.ReadString();
            var netConst = im.ReadByte();
            var actor_data_raw = im.ReadString();
            Log.InfoFormat("{0},{1}", Log.Color_Purple, netConst, actor_data_raw);
            var actorData = JsonConvert.DeserializeObject<ActorData>(actor_data_raw);
            netChannel.AddLoginConnect(actorData, msg.SenderConnection);
            switch (netConst)
            {
                case NetConst.JoinRoom:
                    OnServer_JoinRoom(actorData);
                    break;
            }
        }
    }

    void OnHandlerDisConnection(NetIncomingMessage msg)
    {

        var dis_actor = netChannel.GetActor(msg.SenderEndPoint);
        Log.Info("Acotr :" + dis_actor.name + "LeaveRoom");
        netChannel.RemoveConnection(msg.SenderConnection);
        var res = RoomMgr.Instantce.OtherLeaveRoom(dis_actor.actorGUID);


        //有玩家离开游戏
        var om = netChannel.CreateMessage();
        om.Write(NetConst.PlayerLeavel);
        om.Write(dis_actor.actorGUID.ToString());
        netChannel.SendToAll(om);
    }
    #region 消息处理
    /// <summary>
    /// 连接成功，允许加入房间
    /// </summary>
    /// <param name="actorData"></param>
    void OnServer_JoinRoom(ActorData actorData)
    {
        var result = RoomMgr.Instantce.isCanJoin();
        RoomMgr.Instantce.OtherRequestJointRoom(actorData);
        NetOutgoingMessage om = netChannel.CreateMessage();
        om.Write(NetConst.JointRoom_Resp);
        om.Write(result);
        om.Write(RoomMgr.Instantce.curRoom.ToString());
        netChannel.SendMsgToPlayer(actorData.actorGUID, om, NetDeliveryMethod.ReliableOrdered);

    }
    #endregion


    void OnHandleData(NetIncomingMessage msg)
    {
        var netConst = msg.ReadByte();
        switch(netConst)
        {
            //加入房间
            case NetConst.JointRoom_Resp:
                {
                    bool joinRoom_res = msg.ReadBoolean();
                    if(joinRoom_res)
                    {
                        var joinRoomData = JsonConvert.DeserializeObject<RoomData>( msg.ReadString());
                        RoomMgr.Instantce.HandlerJoinRoomResp(joinRoomData);
                    }
                }
                break;
            case NetConst.PlayerJoin:
                var join_actor = JsonConvert.DeserializeObject<ActorData>(msg.ReadString());
                RoomMgr.Instantce.OtherRequestJointRoom(join_actor);
                break;
            case NetConst.PlayerLeavel:
                var acotrGuid = msg.ReadString();
                RoomMgr.Instantce.OtherLeaveRoom(acotrGuid);
                break;
            case NetConst.StartGame:
                RoomMgr.Instantce.StartGame();
                break;
            case NetConst.OnObjectUpdate:
            case NetConst.OnPlayerUpdate:
            case NetConst.OnPlayerSpwan:
            case NetConst.OnPlayerShot:
                GameManager.Instantce.HandleGameMsg(msg);
                break;
        }
    }


    #region 发送消息
    public void SendStartGame()
    {
        var msg = netChannel.CreateMessage();
        msg.Write(NetConst.StartGame);

        netChannel.SendToAll(msg);
    }

    public void SendNetMsgToAll(NetOutgoingMessage msg,NetDeliveryMethod method = NetDeliveryMethod.ReliableOrdered)
    {
        this.netChannel.SendToAll(msg, method);
    }
    #endregion
}
